package com.lagou.edu.spring.core.impl;

import com.lagou.edu.spring.annotations.Component;
import com.lagou.edu.spring.annotations.ComponentScan;
import com.lagou.edu.spring.annotations.Import;
import com.lagou.edu.spring.annotations.Service;
import com.lagou.edu.spring.core.ApplicationContext;
import com.lagou.edu.spring.core.BeanDefinition;
import com.lagou.edu.spring.io.ResolverUtil;

import java.util.HashSet;
import java.util.Set;

/**
 * com.lagou.edu.spring.core.impl.BeanDefinitionParser
 *
 * @author 大犬
 * @date 2020/4/2
 */
public class BeanDefinitionParser {

    public ApplicationContext applicationContext;

    /**
     * 已经扫描过的包路径
     */
    private Set<String> parsedPackages;
    /**
     * 已经配置好的bean
     */
    private Set<Class> parsedBeanClasses;

    /**
     * 包扫描工具
     */
    private ResolverUtil resolverUtil;


    public BeanDefinitionParser(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        parsedPackages = new HashSet<>();
        parsedBeanClasses = new HashSet<>();
        resolverUtil = new ResolverUtil();
    }

    @SuppressWarnings("unchecked")
    public void parsePackage(String packageName) {
        // 1.判断该包是否已经解析过了，如果已经解析过了，则不再解析
        if (parsedPackages.contains(packageName)) {
            return;
        }
        for (String parsedPackage : parsedPackages) {
            if (packageName.startsWith(parsedPackage)) {
                parsedPackages.add(packageName);
                return;
            }
        }
        // 1.扫描所有包路径下所有包含Component注解的类
        Set<Class> configClassSet = (Set<Class>) resolverUtil.findAnnotated(Component.class, packageName).getClasses();
        Set<Class> serviceClassSet = (Set<Class>) resolverUtil.findAnnotated(Service.class, packageName).getClasses();
        configClassSet.addAll(serviceClassSet);
        // 2.从这些扫描的类中删除已经配置好的类
        configClassSet.removeAll(parsedBeanClasses);
        // 3.所有配置类解析
        configClassSet.forEach(this::parseConfig);
    }

    public void parseConfig(Class configClass) {
        // 1.如果该类已经配置好了，则不需要再配置
        if (parsedBeanClasses.contains(configClass)) {
            return;
        }
        // 2.获取beanName
        String beanName = getBeanName(configClass);
        // 3.获取配置类上的@ComponentScan注解，并进行包扫描
        ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        if (componentScan != null) {
            String packageName = componentScan.value();
            if (packageName.isEmpty()) {
                packageName = configClass.getPackage().getName();
                parsePackage(packageName);
            }
        }
        // 4.获取类上的@Import注解，进行配置类解析处理
        Import anImport = (Import) configClass.getAnnotation(Import.class);
        if (anImport != null) {
            Class[] importClasses = anImport.value();
            for (Class importClass : importClasses) {
                parseConfig(importClass);
            }
        }
        // 5.将configClass封装成beanDefinition
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanName(beanName);
        beanDefinition.setBeanType(configClass);
        // 6.注册到定义中心中去，标记该配置类已经解析过了
        parsedBeanClasses.add(configClass);
        applicationContext.registerBeanDefinition(beanName, beanDefinition);
    }

    private String getBeanName(Class configClass) {
        Component component = (Component) configClass.getDeclaredAnnotation(Component.class);
        Service service = (Service) configClass.getDeclaredAnnotation(Service.class);
        String beanName = null;
        if (component != null) {
            beanName = component.value();
        } else if (service != null) {
            beanName = service.value();
        }
        if (beanName == null || beanName.isEmpty()) {
            beanName = configClass.getSimpleName();
        }
        return beanName;
    }
}
